﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using ecdl.demo.persistence;
using ecdl.demo.model;
using Ninject;

namespace ecdl.demo.model.question {

    public class QuestionDTO : TaskDTO {
        public QuestionDTO() {
            PossibleAnswers = new List<Answer>();
        }

        [XmlElement("Answers")]
        public List<Answer> PossibleAnswers { get; set; }

        [XmlAttribute("text")]
        public String Text { get; set; }

        public override ITask ToModel(ModelFactory factory) {
            Question question = factory.CreateModel<Question>();
            question.PossibleAnswers = PossibleAnswers;
            question.Text = Text;
            return question;
        }
    }

    [Serializable]
    public class Question : ecdl.demo.model.ITask {

        private ITaskPresenter taskPresenter;
        private bool alreadyShuffeled = false;

        [Inject]
        public Question(ITaskPresenter presenter) {
            PossibleAnswers = new List<Answer>();
            taskPresenter = presenter;
        }

        public List<Answer> PossibleAnswers { get; set; }

        public ISet<Answer> CorrectAnswers {
            get {
                if (PossibleAnswers != null) {
                    return new HashSet<Answer>(PossibleAnswers.Where(x => x.IsCorrect));
                } else {
                    return new HashSet<Answer>();
                }
            }
        }

        public String Text { get; set; }

        public int NumberOfAnswers {
            get {
                return PossibleAnswers.Count;
            }
        }

        public int NumberOfCorrectAnswers {
            get {
                return CorrectAnswers.Count;
            }
        }

        public override string ToString() {
            return Text;
        }

        public ITaskEvaluation Evaluate() {
            return new QuestionEvaluation(this, Answer);
        }

        public Answer Answer { get; set; }

        public bool HasAnswer {
            get {
                return Answer != null;
            }
        }

        public int MaxPoints {
            get { return 1; }
        }

        public void ClearAnswer() {
            Answer = null;
        }

        /*public void Initialize(ITaskPresenter presenter, IVolumeProvider pathProvider) {
            presenter.ShowPresenter();
            presenter.CurrentQuestion = this;
        }*/

        public bool CanSubmit {
            get {
                if (Answer != null) {
                    //question is fully answered and ready to be submitted
                    return true;
                } else {
                    //questions can only be submitted if an answer was selected
                    return false;
                }
            }
        }


        public void Activate() {
            if (!alreadyShuffeled) { 
            Shuffle<Answer>(PossibleAnswers);
            alreadyShuffeled = true;
            }
            //Show the taskpresenter
            taskPresenter.CurrentQuestion = this;
            taskPresenter.ShowPresenter();
        }

        private void Shuffle<T>( List<T> list) {
            Random rng = new Random();
            int n = list.Count;
            while (n > 1) {
                n--;
                int k = rng.Next(n + 1);
                T value = list[k];
                list[k] = list[n];
                list[n] = value;
            }
        }

        public void InitializePreconditions() {
            //ignore
        }
    }

    public class QuestionEvaluation : ITaskEvaluation {
        private static readonly int CORRECT_POINTS = 1;
        private static readonly int INCORRECT_POINTS = 0;


        public QuestionEvaluation(Question question, Answer answer) {
            Answer = answer;
            Question = question;
        }
        
        public Answer Answer { get; private set; }
        public Question Question { get; private set; }

        public bool IsCorrect {
            get {
                return Answer.IsCorrect;
            }
        }

        public ITask Task {
            get { return Question; }
        }

        public int Points {
            get {
                if (IsCorrect) {
                    return CORRECT_POINTS;
                } else {
                    return INCORRECT_POINTS;
                }
            }
        }

        public string Cause {
            get { 
                return String.Format("Richtige Antwort: '{0}'.", GetCorrectAnswers());
            }
            set {
                //ignore
            }
        }

        private string GetCorrectAnswers() {
            StringBuilder builder = new StringBuilder();
            foreach (var answer in Question.CorrectAnswers) {
                if (builder.Length > 0) {
                    builder.Append("; ");
                }
                builder.Append(answer.Text);
            }
            return builder.ToString();
        }
    }
}
